package cc.rengu.oltp.utility.util;

import java.math.BigInteger;
import java.nio.ByteBuffer;

/**
 * Byte转换工具类
 * Created by 王成 on 2017/9/27.
 */
public class ByteUtil {
    private static String hexString = "0123456789ABCDEF";
    private static final char[] DIGITS_LOWER = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
    private static final char[] DIGITS_UPPER = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

    /**
     * Hex string to byte byte [ ].
     *
     * @param hex the hex
     * @return the byte [ ]
     */
    public static byte[] hexStringToByte(String hex) {
        int len = (hex.length() / 2);
        byte[] result = new byte[len];
        char[] achar = hex.toCharArray();
        for (int i = 0; i < len; i++) {
            int pos = i * 2;
            result[i] = (byte) (toByte(achar[pos]) << 4 | toByte(achar[pos + 1]));
        }
        return result;
    }

    /**
     * Bytes to hex string string.
     *
     * @param src the src
     * @return the string
     */
    public static String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder("");
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString().toUpperCase();
    }

    private static byte toByte(char c) {
        byte b = (byte) hexString.indexOf(c);
        return b;
    }

    /**
     * Int 2 bytes byte [ ].
     *
     * @param num the num
     * @return the byte [ ]
     */
    public static byte[] int2Bytes(int num) {
        byte[] byteNum = new byte[4];
        for (int ix = 0; ix < 4; ++ix) {
            int offset = 32 - (ix + 1) * 8;
            byteNum[ix] = (byte) ((num >> offset) & 0xff);
        }
        return byteNum;
    }

    /**
     * Int to hex to bytes byte [ ].
     *
     * @param num the num
     * @return the byte [ ]
     */
    public static byte[] intToHexToBytes(short num) {
        byte[] byteNum = new byte[]{(byte) ((num >> 8) & 0xFF), (byte) (num & 0xFF)};
        return byteNum;
    }

    /**
     * Int to hex to byte byte.
     *
     * @param integer the integer
     * @return the byte
     */
    public static byte intToHexToByte(int integer) {
        String hexStr = Integer.toHexString(integer);
        return Byte.valueOf(hexStr, 16);
    }

    /**
     * Int 2 one byte byte.
     *
     * @param num the num
     * @return the byte
     */
    public static byte int2OneByte(int num) {
        return (byte) (num & 0x000000ff);
    }

    /**
     * Two bytes 2 int int.
     *
     * @param buffer the buffer
     * @return the int
     */
    public static int twoBytes2Int(byte[] buffer) {
        return buffer[0] | buffer[1] << 8;
    }

    /**
     * One byte 2 int int.
     *
     * @param byteNum the byte num
     * @return the int
     */
    public static int oneByte2Int(byte byteNum) {
        return byteNum & 0xFF;
    }

    /**
     * Byte to int 16 int.
     *
     * @param b the b
     * @return the int
     */
    public static int byteToInt16(byte b) {
        String result = Integer.toHexString(b & 0xFF);
        return Integer.valueOf(result, 16);
    }

    /**
     * Bytes to int int.
     *
     * @param byteNum the byte num
     * @return the int
     */
    public static int bytesToInt(byte[] byteNum) {
        int num = 0;
        for (int ix = 0; ix < 4; ++ix) {
            num <<= 8;
            num |= (byteNum[ix] & 0xff);
        }
        return num;
    }

    /**
     * Int 2 byte byte [ ].
     *
     * @param num the num
     * @return the byte [ ]
     */
    public static byte[] int2Byte(int num) {
        byte[] byteNum = new byte[4];
        for (int ix = 0; ix < 4; ++ix) {
            int offset = 32 - (ix + 1) * 8;
            byteNum[ix] = (byte) ((num >> offset) & 0xff);
        }
        return byteNum;
    }

    /**
     * Long 2 bytes byte [ ].
     *
     * @param num the num
     * @return the byte [ ]
     */
    public static byte[] long2Bytes(long num) {
        byte[] byteNum = new byte[8];
        for (int ix = 0; ix < 8; ++ix) {
            int offset = 64 - (ix + 1) * 8;
            byteNum[ix] = (byte) ((num >> offset) & 0xff);
        }
        return byteNum;
    }

    /**
     * Bytes 2 long long.
     *
     * @param byteNum the byte num
     * @return the long
     */
    public static long bytes2Long(byte[] byteNum) {
        long num = 0;
        for (int ix = 0; ix < 8; ++ix) {
            num <<= 8;
            num |= (byteNum[ix] & 0xff);
        }
        return num;
    }

    /**
     * Byte 162 float float.
     *
     * @param num the num
     * @return the float
     */
    public static float byte162float(byte[] num) {
        String hexString = bytesToHexString(num);
        Integer temp = Integer.valueOf(hexString.trim(), 16);
        float value = Float.intBitsToFloat(temp.intValue());
        System.out.println(value);
        return value;
    }

    /**
     * Float 2 byte array byte [ ].
     *
     * @param value the value
     * @return the byte [ ]
     */
    public static byte[] float2ByteArray(float value) {
        return ByteBuffer.allocate(4).putFloat(value).array();
    }

    /**
     * Bytes 2 float float.
     *
     * @param b     the b
     * @param index the index
     * @return the float
     */
    public static float bytes2float(byte[] b, int index) {
        int l;
        l = b[index + 0];
        l &= 0xff;
        l |= ((long) b[index + 1] << 8);
        l &= 0xffff;
        l |= ((long) b[index + 2] << 16);
        l &= 0xffffff;
        l |= ((long) b[index + 3] << 24);
        return Float.intBitsToFloat(l);
    }

    /**
     * Byte compare boolean.
     *
     * @param data1 the data 1
     * @param data2 the data 2
     * @param len   the len
     * @return the boolean
     */
    public static boolean byteCompare(byte[] data1, byte[] data2, int len) {
        if (data1 == null && data2 == null) {
            return true;
        }
        if (data1 == null || data2 == null) {
            return false;
        }
        if (data1 == data2) {
            return true;
        }
        boolean bEquals = true;
        int i;
        for (i = 0; i < data1.length && i < data2.length && i < len; i++) {
            if (data1[i] != data2[i]) {
                bEquals = false;
                break;
            }
        }
        return bEquals;
    }

    /**
     * Byte to bit string.
     *
     * @param b the b
     * @return the string
     */
    public static String byteToBit(byte b) {
        return "" + (byte) ((b >> 7) & 0x1) +
                (byte) ((b >> 6) & 0x1) +
                (byte) ((b >> 5) & 0x1) +
                (byte) ((b >> 4) & 0x1) +
                (byte) ((b >> 3) & 0x1) +
                (byte) ((b >> 2) & 0x1) +
                (byte) ((b >> 1) & 0x1) +
                (byte) ((b >> 0) & 0x1);
    }

    /**
     * Print hex string.
     *
     * @param b the b
     */
    public static void printHexString(byte[] b) {
        for (int i = 0; i < b.length; i++) {
            String hex = Integer.toHexString(b[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            System.out.print(hex.toUpperCase());
        }
    }

    /**
     * Exist other char boolean.
     *
     * @param str the str
     * @return the boolean
     */
    public static boolean ExistOtherChar(String str) {
        String numstr = "0123456789";
        int i = 0;
        for (i = 0; i < str.length(); i++) {
            if (numstr.indexOf(str.charAt(i)) == -1) {
                return true;
            }
        }
        return false;
    }

    /**
     * Exist char boolean.
     *
     * @param str the str
     * @return the boolean
     */
    public static boolean ExistChar(String str) {
        String regex = "[a-zA-Z]+$";
        return str.matches(regex);
    }

    /**
     * Legal version boolean.
     *
     * @param str the str
     * @return the boolean
     */
    public static boolean LegalVersion(String str) {
        String regex = "[0-9]+[.][0-9]+[.][0-9]+";
        return str.matches(regex);
    }

    public static byte[] bigIntegerTo32Bytes(BigInteger n) {
        byte[] tmpd;
        if (n == null) {
            return null;
        } else {
            if (n.toByteArray().length == 33) {
                tmpd = new byte[32];
                System.arraycopy(n.toByteArray(), 1, tmpd, 0, 32);
            } else if (n.toByteArray().length == 32) {
                tmpd = n.toByteArray();
            } else {
                tmpd = new byte[32];

                for (int i = 0; i < 32 - n.toByteArray().length; ++i) {
                    tmpd[i] = 0;
                }
                System.arraycopy(n.toByteArray(), 0, tmpd, 32 - n.toByteArray().length, n.toByteArray().length);
            }
            return tmpd;
        }
    }

    public static BigInteger byteToInteger(byte[] b) {
        if (b[0] < 0) {
            byte[] temp = new byte[b.length + 1];
            temp[0] = 0;
            System.arraycopy(b, 0, temp, 1, b.length);
            return new BigInteger(temp);
        } else {
            return new BigInteger(b);
        }
    }

    public static String encodeHexString(byte[] data) {
        return encodeHexString(data, true);
    }

    public static String encodeHexString(byte[] data, boolean toLowerCase) {
        return encodeHexString(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
    }

    protected static String encodeHexString(byte[] data, char[] toDigits) {
        return new String(encodeHex(data, toDigits));
    }

    public static char[] encodeHex(byte[] data) {
        return encodeHex(data, true);
    }

    public static char[] encodeHex(byte[] data, boolean toLowerCase) {
        return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
    }

    protected static char[] encodeHex(byte[] data, char[] toDigits) {
        int l = data.length;
        char[] out = new char[l << 1];
        int i = 0;

        for (int var5 = 0; i < l; ++i) {
            out[var5++] = toDigits[(240 & data[i]) >>> 4];
            out[var5++] = toDigits[15 & data[i]];
        }

        return out;
    }

    public static String getHexString(byte[] bytes) {
        return getHexString(bytes, true);
    }

    public static String getHexString(byte[] bytes, boolean upperCase) {
        String ret = "";

        for (int i = 0; i < bytes.length; ++i) {
            ret = ret + Integer.toString((bytes[i] & 255) + 256, 16).substring(1);
        }

        return upperCase ? ret.toUpperCase() : ret;
    }
}
